﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using GameEngine.Model;
using GameEngine.Model.Data;
using GameEngine.View.Components;
using PureMVC.Interfaces;
using PureMVC.Patterns;
using MapEngine;

namespace GameEngine.View
{
    public class MapMediatorConstants<MyIdType>
        where MyIdType : IComparable<MyIdType> 
    {
        public const String TILEMOUSELEFTBUTTONUP = "TileMapMediator_TileMouseLeftButtonUp";
        public const String ITEMMOUSELEFTBUTTONUP = "TileMapMediator_ItemMouseLeftButtonUp";
        public const String TILEMOUSEENTER = "TileMapMediator_TileMouseEnter";
        public const String TILEMOUSELEAVE = "TileMapMediator_TileMouseLeave";
        public const String TILEMOUSEMOVE = "TileMapMediator_TileMouseMove";
        public const String ITEMSELECTED = "TileMapMediator_ItemSelected";

        public static string GetMediatorNameFromProxy(IMapDataProxy<MyIdType> proxy)
        {
            return proxy.ProxyName + "_TileMapMediator";
        }
    }
    public class MapMediator<MyIdType, MyBaseUIElementType> : Mediator
        where MyIdType : IComparable<MyIdType>
    {
        //Use notification or event...
        public event Action<IThingDataProxy<MyIdType>> OnItemSelected;

        public readonly IWorldDataProxy<MyIdType> WorldProxy;

        //TODO list
        IThingDataProxy<MyIdType> selectedItem;
        public IThingDataProxy<MyIdType> SelectedItem {
            get { return selectedItem; }
            set { 
                selectedItem = value;
                SendNotification(MapMediatorConstants<MyIdType>.ITEMSELECTED, value, this.WorldProxy.WorldName);
                if(OnItemSelected!=null)
                OnItemSelected(value);
            }
        }

        public MapMediator(IMapView<MyIdType, MyBaseUIElementType> viewComponent, IWorldDataProxy<MyIdType> worldProxy)
            : base(MapMediatorConstants<MyIdType>.GetMediatorNameFromProxy(worldProxy.Map), viewComponent)
        {
            this.WorldProxy = worldProxy;
            //MapDataProxyName = proxy.ProxyName;
            //TILEMOUSELEFTBUTTONUP += MediatorName;
            //ITEMMOUSELEFTBUTTONUP += MediatorName;
            //TILEMOUSEENTER += MediatorName;
            //TILEMOUSELEAVE += MediatorName;
            //TILEMOUSEMOVE += MediatorName;
            //ITEMSELECTED += MediatorName;
        }

        //todo private
        public new IMapView<MyIdType, MyBaseUIElementType> ViewComponent
        {
            get { return (IMapView<MyIdType, MyBaseUIElementType>)base.ViewComponent; }
        }

        #region IMediator Members

        /// <summary>
        /// List the <c>INotification</c> names this <c>Mediator</c> is interested in being notified of
        /// </summary>
        /// <returns>The list of <c>INotification</c> names </returns>
        override public IList<string> ListNotificationInterests()
        {

            return new List<string>() { 
                WorldProxy.Map.TILEHEIGHTUPDATED_NOTIFICATION,
                WorldProxy.Map.TYPEUPDATED_NOTIFICATION,
                WorldProxy.Map.SCALEUPDATED_NOTIFICATION,
                WorldProxy.Map.CAMERAPOSITIONUPDATED_NOTIFICATION,
                WorldProxy.Map.TILESUPDATED_NOTIFICATION,
                WorldProxy.Map.CURSORUPDATED_NOTIFICATION,

                ModelFacade<MyIdType>.Instance.Game.TILESIZEUPDATED_NOTIFICATION,
                ModelFacade<MyIdType>.Instance.Game.TILEHEIGHTUNITUPDATED_NOTIFICATION,
                ModelFacade<MyIdType>.Instance.Game.MAXHEIGHTUPDATED_NOTIFICATION,
                ModelFacade<MyIdType>.Instance.Game.MINHEIGHTUPDATED_NOTIFICATION,
                WorldProxy.THINGMOVEWITHMOUSE_NOTIFICATION,

                IThingMediatorConstants<MyIdType>.ITEMMOUSEUP,
                IThingMediatorConstants<MyIdType>.ITEMMOUSEDOWN,
            };
        }

        /// <summary>
        /// Handle <c>INotification</c>s
        /// </summary>
        /// <param name="notification">The <c>INotification</c> instance to handle</param>
        /// <remarks>
        ///     <para>
        ///        Typically this will be handled in a switch statement, with one 'case' entry per <c>INotification</c> the <c>Mediator</c> is interested in. 
        ///     </para>
        /// </remarks>
        override public void HandleNotification(INotification notification)
        {
            switch (notification.Name) {
                case IThingMediatorConstants<MyIdType>.ITEMMOUSEUP:
                    SelectedItem = notification.Body as IThingDataProxy<MyIdType>;
                    //MouseOnItems(true);
                    break;
                case IThingMediatorConstants<MyIdType>.ITEMMOUSEDOWN:
                    //TODO
                    break;
                default:
                    if (notification.Name.Equals(WorldProxy.Map.TYPEUPDATED_NOTIFICATION))
                    {
                        ViewComponent.TileType = WorldProxy.Map.TileType;
                        ViewComponent.MapType = WorldProxy.Map.MapType;
                        ViewComponent.UpdateMapPosition();
                    }
                    else if (notification.Name.Equals(WorldProxy.Map.TILEHEIGHTUPDATED_NOTIFICATION))
                    {
                        TileVO tile = notification.Body as TileVO;
                        ViewComponent.UpdateTile(tile.Position);
                    }
                    else if (notification.Name.Equals(WorldProxy.Map.SCALEUPDATED_NOTIFICATION))
                    {
                        ViewComponent.ScaleMap(WorldProxy.Map.Scale);
                        ViewComponent.UpdateMapPosition();
                    }
                    else if (notification.Name.Equals(WorldProxy.Map.CAMERAPOSITIONUPDATED_NOTIFICATION))
                    {
                        ViewComponent.MapPosition = WorldProxy.Map.CameraPosition;
                        ViewComponent.UpdateMapPosition();
                    }
                    else if (notification.Name.Equals(WorldProxy.Map.TILESUPDATED_NOTIFICATION))
                    {
                        ViewComponent.MapSize = WorldProxy.Map.Size;
                        ViewComponent.UpdateMap();
                        ViewComponent.MapPosition = WorldProxy.Map.CameraPosition;
                        ViewComponent.UpdateMapPosition();

                    }
                    else if (notification.Name.Equals(WorldProxy.Map.CURSORUPDATED_NOTIFICATION))
                    {
                        SetMouseCursor(notification.Body as Cursor);
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.TILESIZEUPDATED_NOTIFICATION))
                    {
                        ViewComponent.TileSize = ModelFacade<MyIdType>.Instance.Game.TileSize;
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.MAXHEIGHTUPDATED_NOTIFICATION))
                    {
                        ViewComponent.MaxMapHeight = ModelFacade<MyIdType>.Instance.Game.MaxHeight;
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.MINHEIGHTUPDATED_NOTIFICATION))
                    {
                        ViewComponent.MinMapHeight = ModelFacade<MyIdType>.Instance.Game.MinHeight;
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.TILEHEIGHTUNITUPDATED_NOTIFICATION))
                    {
                        ViewComponent.TileHeightUnit = ModelFacade<MyIdType>.Instance.Game.TileHeightUnit;
                    }
                    else if (notification.Name.Equals(WorldProxy.THINGMOVEWITHMOUSE_NOTIFICATION)) {
                        MoveItemWithMouse(notification.Body as IThingDataProxy<MyIdType>);
                    }
                    break;
            }
        }

        /// <summary>
        /// Called by the View when the Mediator is registered
        /// </summary>
        override public void OnRegister()
        {
            ViewComponent.MaxMapHeight = ModelFacade<MyIdType>.Instance.Game.MaxHeight;
            ViewComponent.MinMapHeight = ModelFacade<MyIdType>.Instance.Game.MinHeight;
            ViewComponent.TileSize = ModelFacade<MyIdType>.Instance.Game.TileSize;
            ViewComponent.TileHeightUnit = ModelFacade<MyIdType>.Instance.Game.TileHeightUnit;


            ViewComponent.TileType = WorldProxy.Map.TileType;
            ViewComponent.ScaleMap(WorldProxy.Map.Scale);
            ViewComponent.MapSize = WorldProxy.Map.Size;

            ViewComponent.Initialize(WorldProxy.Map.GetTileHeight);

            ViewComponent.MapPosition = WorldProxy.Map.CameraPosition;

            foreach (var view in WorldProxy.Map.SimpleViews) {
                var v = ViewFacade<MyIdType, MyBaseUIElementType>.Instance.CreateViewInstance();
                v.Initialize(view);
                ViewComponent.AddUIElement(v,new Point(0,0),0);
            }
                

            //ViewComponent.UpdateMapPosition();
            //Point p = GetMapScreenSize();
            //SetViewSize(p.X, p.Y);

            ViewComponent.TileMouseEnter += new TileMouseEventDelegate(ViewComponent_TileMouseEnter);
            ViewComponent.TileMouseLeave += new TileMouseEventDelegate(ViewComponent_TileMouseLeave);
            ViewComponent.TileMouseLeftButtonUp += new TileMouseButtonEventDelegate(ViewComponent_TileMouseLeftButtonUp);
            //ViewComponent.TileMouseMove += new MapUC.MouseEventDelegate(ViewComponent_TileMouseMove);
            
            ViewComponent.OnLayoutUpdate += new Action<Point>(ViewComponent_OnLayoutUpdate);
            //proxy.ti
            //itemMediator.OnHeightChange += new Action<IThingDataProxy>(itemMediator_OnHeightChange);
            //ItemMediator<IItemView>.Instance.OnPositionChange += new Action<IThingDataProxy>(itemMediator_OnMapPositionChange);
        }

        /// <summary>
        /// Called by the View when the Mediator is removed
        /// </summary>
        override public void OnRemove()
        {
            //Facade.RemoveProxy(WorldProxy.Map.ProxyName);
        }

        #endregion

        public void MouseOnItems(bool value)
        {
            ViewComponent.MouseOnItems(value);
        }

        public void SetMouseCursor(Cursor cursor) {
            ViewComponent.Cursor = cursor;
        }

        public void RegisterMapNavigator(IMapNavigator<MyIdType,MyBaseUIElementType> view)
        {
            view.OnMapNavigate += new Action<Point>(ViewComponent_OnMapNavigate);
        }

        public void RegisterMapZoom(IMapZoom<MyIdType, MyBaseUIElementType> view)
        {
            view.OnMapZoom += new Action<double>(ViewComponent_OnMapZoom);
        }

        #region ViewComponent Events
        void ViewComponent_TileMouseMove(Point p, MouseEventArgs e)
        {
            SendNotification(MapMediatorConstants<MyIdType>.TILEMOUSEMOVE, p,WorldProxy.WorldName);
        }

        void ViewComponent_TileMouseLeftButtonUp(Point p, MouseButtonEventArgs e)
        {
            if (SelectedItem != null)
            {
                //SendNotification(MyGameFacade.REMOVEITEMFROMMAP_NOTIFICATION, SelectedItem);
                //SilverlightItemMediator.Instance.RemoveProxy(SelectedItem);
                //SendNotification(MyGameFacade.ADDITEMTOGAME_COMMAND, SelectedItem, MyGameDataProxy.Instance.CurrentView.ToString());
                //Facade.RegisterMediator(SelectedItem);
                //SelectedItem.Position = position;
                //Map.AddItem(SelectedItem);
                SelectedItem.MovingWithMouse = false;
                SelectedItem = null;
                MouseOnItems(true);
                //BuildingsMenu.UnselectItem();
            }
            SendNotification(MapMediatorConstants<MyIdType>.TILEMOUSELEFTBUTTONUP, p,WorldProxy.WorldName);
        }

        void ViewComponent_TileMouseLeave(Point p, MouseEventArgs e)
        {
            if (SelectedItem != null && SelectedItem.MovingWithMouse)
            {
                SelectedItem.Position = p;
                //SendNotification(MyGameFacade.REMOVEITEMFROMMAP_NOTIFICATION, SelectedItem);
            }
            SendNotification(MapMediatorConstants<MyIdType>.TILEMOUSELEAVE, p,WorldProxy.WorldName);
        }

        void ViewComponent_TileMouseEnter(Point p, MouseEventArgs e)
        {
            if (SelectedItem != null && SelectedItem.MovingWithMouse)
            {
                SelectedItem.Position = p;
                //SendNotification(MyGameFacade.ADDITEMTOMAP_NOTIFICATION, SelectedItem);
            }
            SendNotification(MapMediatorConstants<MyIdType>.TILEMOUSEENTER, p,WorldProxy.WorldName);
        }

        void ViewComponent_OnLayoutUpdate(Point p)
        {
            /*
            switch (proxy.type)
            {
                case MapDataProxy.Type.Normal:
                    ViewComponent.MapSize = proxy.Size;
                    break;
                case MapDataProxy.Type.Perlin:
                    float aux = 2f;//valor para aparecer no ecra todo
                    //float aux = 0.75f;
                    //float aux = 1f;
                    if (ViewComponent.MapContainer.ActualWidth > 0)
                    {
                        if (ViewComponent.MapContainer.ActualWidth < ViewComponent.MapContainer.ActualHeight)
                        {
                            ViewComponent.MapSize = new Point(
                            Math.Round(aux * ViewComponent.MapContainer.ActualWidth / (ViewComponent.TileSize.X)),
                            Math.Round(aux * ViewComponent.MapContainer.ActualWidth / (ViewComponent.TileSize.Y)));
                        }
                        else
                        {
                            ViewComponent.MapSize = new Point(
                            Math.Round(aux * ViewComponent.MapContainer.ActualHeight / (ViewComponent.TileSize.X)),
                            Math.Round(aux * ViewComponent.MapContainer.ActualHeight / (ViewComponent.TileSize.Y)));
                        }
                    }
                    break;
            }*/
            //ViewComponent.UpdateMap();
            ViewComponent.UpdateMapPosition();
            ViewComponent.ScaleMap(WorldProxy.Map.Scale);
        }

        void ViewComponent_OnMapZoom(double obj)
        {
            WorldProxy.Map.Scale = (float)obj * 10 / 10;
        }

        void ViewComponent_OnMapNavigate(Point obj)
        {
            switch (WorldProxy.Map.MapType)
            {
                case MapType.Isometric:
                    if (obj.Y > 0)
                        WorldProxy.Map.CameraPosition = new Point(
                            WorldProxy.Map.CameraPosition.X - obj.Y,
                            WorldProxy.Map.CameraPosition.Y + obj.Y);
                    else if (obj.Y < 0)
                        WorldProxy.Map.CameraPosition = new Point(
                            WorldProxy.Map.CameraPosition.X - obj.Y,
                            WorldProxy.Map.CameraPosition.Y + obj.Y);
                    else if (obj.X > 0)
                        WorldProxy.Map.CameraPosition = new Point(
                            WorldProxy.Map.CameraPosition.X + obj.X,
                            WorldProxy.Map.CameraPosition.Y + obj.X);
                    else if (obj.X < 0)
                        WorldProxy.Map.CameraPosition = new Point(
                            WorldProxy.Map.CameraPosition.X + obj.X,
                            WorldProxy.Map.CameraPosition.Y + obj.X);
                    break;
                case MapType.Top:
                    WorldProxy.Map.CameraPosition = new Point(
                        WorldProxy.Map.CameraPosition.X + obj.X,
                        WorldProxy.Map.CameraPosition.Y + obj.Y);
                    break;
            }
        }
      
        #endregion

        public void SetViewSize(double width, double height)
        {
            ViewComponent.ViewSize=new Point(width,height);
            //ViewComponent.UpdateMapPosition();
            
        }

        public void MoveItemWithMouse(IThingDataProxy<MyIdType> Item)
        {
            Item.MovingWithMouse = true;
            //SelectedItem = menuItem.Replicate();
            //SilverlightItemMediator.Instance.AddProxy(SelectedItem, MyGameFacade.Instance().CreateViewInstance(SelectedItem));
            SelectedItem = Item;
            MouseOnItems(false);
        }

        //abstract public Point GetMapScreenSize();
    }
}
